#include"WebPageQuery.h"
#include"SloSplitTool.h"
#include"nlohmann/json.hpp"
#include"TcpConnection.h"
#include"LRU.h"
#include"Redis.h"
#include<iostream>
#include<fstream>
#include<sstream>
#include<vector>
#include<algorithm> 
#include<map>
#include<cmath>
#include<queue>
using std::ifstream;
using std::stringstream;
using std::istringstream;
using std::cout;
using std::string;
using std::vector;
using std::map;
using std::priority_queue;
WebPageQuery::WebPageQuery(const string &sentence,TcpConnectionPtr conn,LRU&lru)
:_conn(conn),
_lru(lru),
_lock()
{
    loadLibrary();
    //去除换行
    string content=removeNorR(sentence);
    map<string,int> totalSentence;
    vector<string> wordList=SloSplitTool::getInstance()->cut(content);
    for(auto it=wordList.begin();it!=wordList.end();){
        if(stopMap.count(*it)!=0){
            it=wordList.erase(it);
        }else{
            ++totalSentence[*it];
            ++it;
        }
    }
    for(auto ele:wordList){
        cout<<ele<<"\n";
    }
     cout<<"end"<<"\n";
    vector<double> vec;
    double geoPower=0;
    for(auto ele:totalSentence){
        double TF=ele.second;
        double BF=1;
        double IDF=log2(1/(BF+1));
        double power=TF*IDF;
        geoPower+=pow(power,2);
        vec.push_back(power);
    }
    for(auto &ele:vec){
        ele=ele/sqrt(geoPower);
    }
    executeQuery(wordList,vec);
}//const string &sentence
void WebPageQuery::loadLibrary(){
    //载入去重网页偏移库
    ifstream ifs("/home/zzh/cpp/project/v1_project/search/data/newoffset.dat");
    if(ifs.is_open()){
        cout<<"file open success!\n";
    }else{
        cout<<"file open fail !\n";
        return;
    }
    stringstream buf;
    buf<<ifs.rdbuf();
    string line;
    int count=0;
    while(getline(buf,line)){
        count++;
        int id,off,length;
        istringstream iss(line);
        iss>>id>>off>>length;
        _offsetLib.insert({id,{off,length}});
    }
    ifs.close();
    //
    vector<string> stopfile;
    stopfile.push_back("/home/zzh/cpp/project/v1_project/yuliao/stop_words_zh.txt");
    stopfile.push_back("/home/zzh/cpp/project/v1_project/yuliao/stop_words_eng.txt");
    for(auto ele:stopfile){
    ifstream ifs(ele);
        if(ifs.is_open()){
            cout<<"file open success!\n";
        }else{
            perror("file open fail\n");
            return;
        }
        //读入整个文本文件
        stringstream buf;
        buf<<ifs.rdbuf();
        string content=buf.str();
        istringstream iss(content);
        string word;
        while(iss>>word){
            ++stopMap[word];
        }
    }
    //
    ifs.open("/home/zzh/cpp/project/v1_project/search/data/invertIndex.dat");
    if(ifs.is_open()){
        cout<<"file open success!\n";
    }else{
        cout<<"file open fail !\n";
        return;
    }
    buf.clear();
    buf<<ifs.rdbuf();
    while(getline(buf,line)){
        string word;
        int id;
        double power;
        istringstream iss(line);
        iss>>word>>id>>power;
        _invertIndexTable[word].insert({id,power});
        while(iss>>id>>power){
            _invertIndexTable[word].insert({id,power});
        }
    }
    ifs.close();
}
bool WebPageQuery::executeQuery(vector<string> &wordList,vector<double>& sVec){
    //将每个词pair中的int（索引）导入一个set
    vector<set<int>> setList;
    for(auto ele:wordList){
        set<int> oneWordIndex;
        for(auto sele:_invertIndexTable[ele]){
        oneWordIndex.insert(sele.first);
        }
        setList.push_back(oneWordIndex);
    }
    for(auto ele:wordList){
        cout<<ele<<" ";
    }
    cout<<"\n";

    // for(auto ele:setList){
    //     for(auto sele:ele){
    //         cout<<sele<<" ";
    //     }
    //     cout<<"\n";
    // }
    //取交集
    set<int> nset=intersectMultipleSets(setList);
    cout<<"nset size:"<<nset.size()<<"\n";
    for(auto ele:nset){
        cout<<ele<<" ";
    }

    //将每个词的pair导入一个map方便找到权重
    vector<pair<int,vector<double>>> vecList;
    for(auto ele:nset){
        vector<double> vec;
        for(auto wele:wordList){
            for(auto db:_invertIndexTable[wele])
            if(db.first==ele){
                vec.push_back(db.second);
            }
        }
        vecList.push_back({ele,vec});
    }
    priority_queue<SentenceRes> pque;
    for(auto vel:vecList){
        double power=cosineSimilarity(sVec,vel.second);
        pque.push(SentenceRes(vel.first,power));
    }
    ifstream ifs("/home/zzh/cpp/project/v1_project/search/data/newpagelib.dat");
    nlohmann::json json_array;
    int i=0;
    Redis red;
    red.connect("127.0.0.1",6379);
    while(!pque.empty()&&i<10){
        int idx=pque.top().getIndex();
        string buf;
        if((buf=red.get(std::to_string(idx)))!=string()){
            cout<<"read from redis!\n";
             _lru.put(idx,idx);
             json_array[i]=buf;
             unique_lock<mutex> ul(_lock);
             pque.pop();
             ul.unlock();
             i++;
             continue;
        }
        //读取磁盘文件
        size_t off=_offsetLib[idx].first;
        size_t length=_offsetLib[idx].second; 
        buf.resize(length);
        ifs.seekg(off);
        ifs.read(&buf[0],length);
        _lru.put(idx,idx);
        red.set(std::to_string(idx),buf);
        json_array[i]=buf;
        pque.pop();
        i++;
    }
    _conn->sendInLoop(json_array.dump());
    //读文件
    // ifstream ifs("/home/zzh/cpp/project/v1_project/search/data/newpagelib.dat");
    // for(size_t idx=1;idx<=newOffset.size();idx++){
    //     set<string> onePageWord;
    //     size_t off=newOffset[idx].first;
    //     size_t length=newOffset[idx].second;
    //     string buf; 
    //     buf.resize(length);
    //     ifs.seekg(off);
    //     ifs.read(&buf[0],length);    
    // }
    return true;
}

// 定义一个函数来计算多个 set<int> 的交集
set<int> WebPageQuery::intersectMultipleSets(const vector<set<int>>& sets) {
    if (sets.empty()) {
        cout<<"sets is empty";
        return {}; // 返回一个空集合
    }

    // 初始化结果集为第一个集合
    std::set<int> result = sets[0];

    // 逐步计算交集
    for (size_t i = 1; i < sets.size(); ++i) {
        std::set<int> tempResult;
        std::set_intersection(result.begin(), result.end(),
                             sets[i].begin(), sets[i].end(),
                             std::inserter(tempResult, tempResult.begin()));
        result = std::move(tempResult); // 将临时结果赋值给结果集
    }

    return result;
}

// 计算向量的模
double WebPageQuery::vectorMagnitude(const std::vector<double>& vec) {
    double sum = 0.0;
    for (double val : vec) {
        sum += val * val;
    }
    return std::sqrt(sum);
}

// 计算两个向量的点积
double WebPageQuery::dotProduct(const std::vector<double>& vec1, const std::vector<double>& vec2) {
    assert(vec1.size() == vec2.size());
    double sum = 0.0;
    for (size_t i = 0; i < vec1.size(); ++i) {
        sum += vec1[i] * vec2[i];
    }
    return sum;
}

// 计算两个向量的余弦相似度
double WebPageQuery::cosineSimilarity(const std::vector<double>& vec1, const std::vector<double>& vec2) {
    assert(vec1.size() == vec2.size());
    double dotProd = dotProduct(vec1, vec2);
    double mag1 = vectorMagnitude(vec1);
    double mag2 = vectorMagnitude(vec2);
    
    if (mag1 == 0.0 || mag2 == 0.0) {
        return 0.0; // 如果任意向量的模为0，则相似度为0
    }
    
    return dotProd / (mag1 * mag2);
}
string WebPageQuery::removeNorR(const string&input){
    std::string result;
    result.reserve(input.size()); // 预留空间，提高性能

    for (char ch : input) {
        if (ch != '\n' && ch != '\r') {
            result.push_back(ch);
        }
    }

    return result;
}






SentenceRes::SentenceRes(int index,double sim):_index(index),_sim(sim){}
bool SentenceRes::operator<(const SentenceRes&rhs)const{
    return _sim<rhs._sim;
}
int SentenceRes::getIndex()const
{
    return _index;
}
void SentenceRes::print()const{
    cout<<"index:"<<_index<<" sim:"<<_sim<<"\n";
}




